package com.treasury.glasses;

import com.treasury.glasses.controller.LoginController;
import com.treasury.glasses.controller.SceneController;
import com.treasury.glasses.domain.ProgramUser;
import com.treasury.glasses.persistence.FileAccess;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;


/**
 * Main method and starting point of the entire glasses program.
 * @author <a href="mailto:glasses@audienz.eu">Jean-Luc Burot</a>
 */

public class Main extends Application {
    /**
     * Text length limit of all TextFields.
     */
    public static final int TEXTFIELD_MAXLENGTH = 255;
    
    /**
     * Privately handled SceneController given public by the getSceneController
     * method.
     */
    private static SceneController sceneController;
    
    /**
     * Privately handled LoginController given public by the getLoginController
     * method.
     */
    private static LoginController loginController;
    
    /**
     * Privately handled Stage given public by the getStage method.
     */
    private static Stage stage;
    
    /**
     * Privately handled ProgramUser given public by the getLoggedInUser method.
     */
    private static ProgramUser loggedInUser;
    
    /**
     * Privately handled ProgramUser given public by the getSystemUser method.
     */
    private static ProgramUser systemUser;
    
    /**
     * EntityManagerFactory once created at the beginning of the program
     * choosing wich persistent unit to take.
     */
    private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("GlassesPU");
    
    /**
     * Privately handled EntityManager given public by the getEntityManager
     * method.
     */
    private static EntityManager em;
    
    /**
     * Privately handeled FileAccess given public by the getFileAccess method.
     */
    private static FileAccess fa;
    
    /**
     * Creates an instance of the FileAccess and returns it.
     * @return FileAccess
     */
    public static FileAccess getFileAccess() {
        if (fa == null) {
            fa = new FileAccess();
        }
        
        return fa;
    }
    
    /**
     * Creates the EntityManager or gives back the already created
     * instance of it.
     * @return EntityManager
     */
    public static EntityManager getEntityManager() {
        if (em == null) {
            em = emf.createEntityManager();
        }
        
        return em;
    }
    
    /**
     * Returns the SceneController.
     * @return SceneController
     */
    public static SceneController getSceneController() {
        return sceneController;
    }
    
    /**
     * Sets the SceneController.
     * @param contoller SceneController
     */
    public static void setSceneController(final SceneController contoller) {
        sceneController = contoller;
    }
    
    /**
     * Returns the LoginController.
     * @return LoginController
     */
    public static LoginController getLoginController() {
        return loginController;
    }
    
    /**
     * Sets the LoginController.
     * @param controller LoginController
     */
    public static void setLoginController(final LoginController controller) {
        loginController = controller;
    }
    
    /**
     * Returns the once at the beginning created stage for further use through
     * the program.
     * @return Stage
     */
    public static Stage getStage() {
        return stage;
    }
    
    /**
     * Creates and gets the System user.
     * @return System user
     */
    public static ProgramUser getSystemUser() {
        if (systemUser == null) {
            // Create System ProgramUser.
            systemUser = new ProgramUser();
            systemUser.setFirstName("System");
            systemUser.setLastName("System");
            systemUser.setUsername("System");
            systemUser.setPassword("System");
        }
        
        return systemUser;
    }
    
    /**
     * Gets the logged in ProgramUser for global information.
     * @return ProgramUser
     */
    public static ProgramUser getLoggedInUser() {
        return loggedInUser;
    }
    
    /**
     * Sets the logged in ProgramUser for global information.
     * @param user ProgramUser
     */
    public static void setLoggedInUser(final ProgramUser user) {
        loggedInUser = user;
    }
    
    /**
     * Limits a TextField's allowed characters.
     * @param textField TextField
     * @param maxLength Max length of text in TextField
     */
    public static void addTextLimiter(final TextField textField, final int maxLength) {
        textField.textProperty().addListener(new ChangeListener<String>() {

            @Override
            public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
                if (newValue.length() > maxLength) {
                    textField.setText(oldValue);
                }
            }
        });
    }
    
    @Override
    public final void start(final Stage firstStage) throws Exception {
        Parent mask = FXMLLoader.load(getClass()
                                .getResource("/fxml/Scene.fxml"));
        
        Scene scene = new Scene(mask);
        scene.getStylesheets().add("/styles/Styles.css");
        
        firstStage.setTitle("Glasses");
        firstStage.setScene(scene);
        firstStage.show();
        
        Main.stage = firstStage;
    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(final String[] args) {
        launch(args);
    }
}
